package ScanLineAlghorithms;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.ListIterator;

import DataModel.LayoutManager.CEdge;
import DataModel.LayoutManager.CRectangle;
import DataModel.SegmentTree.SegmentTree;
import DataModel.SegmentTree.SegmentTreeImpl;
/**
 * Implementation of rectangles intersection using scan line and segment tree
 * @author Guy
 *
 */
public class RectanglesIntersection {
	/**
	 * This function implements rectangles inersection algorithm based on scan line.
	 * @param recsList - linked list of rectangles among which we want to find intersecting pairs
	 *        recsConnected - Hash table that contains intersection result. Key : rectangle Data : list of rectangles intersecting with the key
	 * @return void
	 */
	@SuppressWarnings("unchecked")
	public static void Activate(LinkedList<CRectangle> recsList, Hashtable<Long, LinkedList<CRectangle>> recsConnected)
	{	
		Hashtable<Long,CRectangle> recIdHash = new Hashtable<Long, CRectangle>();
		Hashtable<Long,Hashtable<Long,Boolean>> tempResult = new Hashtable<Long, Hashtable<Long, Boolean>>();
		initTempResultsHash(tempResult,recIdHash,recsList);
		Hashtable<Long, LinkedList<CEdge>> xScale = ScanLineFunctions.initEndpoints(recsList , 'x');
		ArrayList<CEdge> yEdges = ScanLineFunctions.extractEdges(recsList, 'y');
		SegmentTree statusTree = new SegmentTreeImpl(yEdges,'y');
		
		LinkedList keys = new LinkedList(xScale.keySet());
		Collections.sort(keys);
		
		ListIterator itKeys  = keys.listIterator();
		
		while (itKeys.hasNext()) {
			Long key = (Long)itKeys.next();
			LinkedList<CEdge> edges = xScale.get(key);
			ListIterator itEdges = edges.listIterator();
			while (itEdges.hasNext()) {
				CEdge edge = (CEdge) itEdges.next();
				ArrayList<Long> queryRes =  new ArrayList<Long>();
				if (edge.getEndPoint().y<=edge.getStartPoint().y) {
					statusTree.remove(edge);
					queryRes = statusTree.rangeQuery(edge.getEndPoint().y, edge.getStartPoint().y);
					
				}
					if (edge.getStartPoint().y<=edge.getEndPoint().y) {
					queryRes = statusTree.rangeQuery(edge.getStartPoint().y,edge.getEndPoint().y);
					statusTree.insert(edge);
				}
				updateTempResults(tempResult,queryRes,edge.getID());
			}
			
		}
		//update the result table
		createFinalResults( tempResult, recsConnected, recIdHash);
	}
	private static void initTempResultsHash(Hashtable<Long,Hashtable<Long,Boolean>> tempResults,Hashtable<Long,CRectangle> recIdHash,LinkedList<CRectangle> recsList) {
		ListIterator it = recsList.listIterator();
		while(it.hasNext()) {
			CRectangle rec = (CRectangle) it.next();
			long recId = rec.getID();
			Hashtable<Long,Boolean> recHashIntersec =  new Hashtable<Long, Boolean>();
			tempResults.put(recId, recHashIntersec);
			recIdHash.put(recId, rec);
		}
	}
	private static void updateTempResults(Hashtable<Long,Hashtable<Long,Boolean>> tempResults,ArrayList<Long> queryRes,long id) {
		ListIterator it = queryRes.listIterator();
		while(it.hasNext()) {
			Long recId = ((Long) it.next());
			if (recId.longValue()==id) continue;
			tempResults.get(id).put(recId, true);
			tempResults.get(recId).put(id,true);
		}
	}
	@SuppressWarnings("unchecked")
	private static void createFinalResults(Hashtable<Long,Hashtable<Long,Boolean>> tempResults,Hashtable<Long, LinkedList<CRectangle>> recsConnected,Hashtable<Long,CRectangle> recIdHash){
		
		LinkedList keys = new LinkedList(tempResults.keySet());
		ListIterator it = keys.listIterator();
		while(it.hasNext()) {
			Long key = (Long) it.next();
			LinkedList<CRectangle> recsList =  new LinkedList();
			LinkedList idList = new LinkedList(tempResults.get(key).keySet());
			ListIterator itRecsId = idList.listIterator();
			while (itRecsId.hasNext()) {
				recsList.add(recIdHash.get(itRecsId.next()));
			}
			recsConnected.put(key, recsList);
		}
	}

	
}
